/*
 * File:        serverInfoList.h
 * Authors:     Jonathan Kotker (ee122-bw) and Shaan Mulchandani (ee122-bv)
 * Description: This header file defines the list of information
 *              of servers being tracked.
 */

#ifndef _SERVERINFOLIST_H
#define	_SERVERINFOLIST_H

#include "constants.h"
#include "serverInfo.h"

#include <stdio.h>
#include <stdlib.h>

typedef struct {
    /* Head of the linked list. */
    serverInfo* head;

    /* Tail of the linked list. */
    serverInfo* tail;

    /* Array representation of the linked list. */
    serverInfo** infoArray;

    /* Number of servers in the linked list. */
    int numServers;
} serverInfoList;

/*
 * Initializes the list of server information.
 */
void initServerInfoList(serverInfoList* list) {
    list->head = NULL;
    list->tail = NULL;
    list->infoArray = NULL;
    list->numServers = 0;
};

/*
 * Returns the server information associated with the given
 * server ID, and NULL otherwise.
 */
serverInfo* accessServerInfo(serverInfoList* list, int serverId) {
    if (list == NULL) return NULL;

    return (serverId < list->numServers) ? list->infoArray[serverId] : NULL;
};

/*
 * Deallocates the dynamic memory allocated to this list.
 */
void clearServerInfoList(serverInfoList* list) {
    serverInfo* currNode;
    serverInfo* nextNode;
    currNode = list->head;

    while (currNode != NULL) {
        nextNode = currNode->next;
        free(currNode);
        currNode = nextNode;
    }

    if (list->infoArray != NULL) {
        free(list->infoArray);
    }
};

/*
 * Adds the new server information to the server information list.
 */
void addServerInfo(serverInfoList* list, serverInfo* newServerInfo) {
    if (list == NULL) return;

    newServerInfo->next = NULL;

    if (list->head == NULL) {
        list->head = newServerInfo;
        list->tail = newServerInfo;

        newServerInfo->prev = NULL;
    } else {
        newServerInfo->prev = list->tail;
        list->tail->next = newServerInfo;
        list->tail = newServerInfo;
    }
};

/*
 * Converts the server information list into an array for more
 * efficient information retrieval. This is only done once.
 */
void convertToArray(serverInfoList* list) {
    if ((list == NULL) || (list->head == NULL)) return;

    /* We only convert the list to array once, since
     * the list will not change once it is converted. */
    if (list->infoArray == NULL) {
        // Do one pass to figure out how many servers there are.
        list->numServers = 0;

        serverInfo* currNode = list->head;
        while (currNode) {
            list->numServers++;
            currNode = currNode->next;
        }

        int numServers = list->numServers;
        if (numServers > 0) {
            list->infoArray = (serverInfo**)
                    malloc(numServers * sizeof (serverInfo *));
            if (list->infoArray == NULL) {
                fprintf(stdout, "No free space available to allocate.\n");
                clearServerInfoList(list);
                exit(EXIT_FAILURE);
            }

            // Do another pass to add pointers into the array.
            int i;
            currNode = list->head;
            
            for (i = 0; i < numServers; i++) {
                list->infoArray[i] = currNode;
                currNode = currNode->next;
            }
        }
    }
};

#endif	/* _SERVERINFOLIST_H */
